#include <iostream>
#include <cstdint>
#include <memory>
#include <vector>
#include <unordered_map>
#include <functional>
#include <unistd.h>

using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;
//定时器任务类
class TimerTask
{
    private:
        uint64_t _id;         //定时器任务对象id
        uint32_t _timeout;    //定时任务的超时时间
        bool _canceled;       //false-表示定时任务没有被取消，true-表示定时任务被取消了
        TaskFunc _task_cb;    //定时器对象要执行的定时任务
        ReleaseFunc _release; //用于删除TimerWheel中保存的定时器对象信息
    public:
        TimerTask(uint64_t id, uint32_t delay, const TaskFunc& task_cb)
        :_id(id), _timeout(delay), _task_cb(task_cb), _canceled(false)
        {}
        ~TimerTask()
        {
            if(_canceled == false) _task_cb();
            _release();
        }
        void Cancel()
        {
            _canceled = true;
        }
        void SetRelease(const ReleaseFunc& cb)
        {
            _release = cb;
        }
        uint32_t DelayTime()
        {
            return _timeout;
        }
};

//时间轮类的设计
class TimerWheel
{
    private:
        using WeakTask = std::weak_ptr<TimerTask>;
        using PtrTask = std::shared_ptr<TimerTask>;
        
        int _tick;         //当前秒针，走到哪了释放到哪里，就相当于执行哪里的任务
        int _capacity;     //表盘最大数量 --- 其实就是最大延迟时间
        std::vector<std::vector<PtrTask>> _wheel;
        std::unordered_map<uint64_t, WeakTask> _timers;
    private:
        void RemoveTimer(uint64_t id)
        {
            auto it = _timers.find(id);
            if(it != _timers.end())
            {
                _timers.erase(id);
            }
        }
    public:
        //初始化不取决于初始化列表的顺序，取决于定义的顺序
        TimerWheel():_capacity(60), _tick(0), _wheel(_capacity){}

        //添加定时任务
        void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc& cb)
        {
            PtrTask pt(new TimerTask(id, delay, cb)); //实例化任务对象
            pt->SetRelease(std::bind(&TimerWheel::RemoveTimer, this, id)); //当这个定时任务被销毁的时候，需要从unordered_map中把信息移除掉
            int pos = (_tick + delay) % _capacity; //计算出添加的位置.表盘是一个环，要回绕
            _wheel[pos].push_back(pt);             //把任务添加进表盘位置
            _timers[id] = WeakTask(pt);

        }
        //刷新/延迟定时任务
        void TimerRefresh(uint64_t id)
        {
            //通过保存的定时器对象的weak_ptr,构造出一个sheard_ptr出来， 添加进轮子中
            auto it = _timers.find(id);
            if(it == _timers.end())
            {
                return; //没找到定时任务，没法刷新
            }
            //lock:获取weak_ptr管理的对象对应的shared_ptr
            //若任务对象被销毁，则返回空的 shared_ptr，
            //如果存在，则返回一个 shared_ptr，增加引用计数，确保对象在使用期间不会被销毁.
            PtrTask pt = it->second.lock();
            int delay = pt->DelayTime();
            int pos = (_tick + delay) % _capacity; //计算出添加的位置.表盘是一个环，要回绕
            _wheel[pos].push_back(pt);             //把任务添加进表盘位置
        }
        //取消定时任务
        void TimerCancel(uint64_t id)
        {
            auto it = _timers.find(id);
            if(it == _timers.end())
            {
                return; //没找到定时任务，没法刷新
            }
            PtrTask pt = it->second.lock();
            if(pt) pt->Cancel();
        }
        //运行定时任务
        //这个函数每秒执行一次，相当于秒针向后走一步
        void RunTimerTask()
        {
            _tick = (_tick + 1) % _capacity;
            _wheel[_tick].clear(); //清空指定位置的数组，就会把数组中保存的所有管理定时对象的shared_ptr释放掉
        }
};

class Test
{
    public:
    Test() {std::cout << "构造" << std::endl;}
    ~Test() {std::cout << "析构" << std::endl;}
};

void DelTest(Test *t)
{
    delete t;
}

int main()
{
    TimerWheel tw;

    Test *t = new Test();

    tw.TimerAdd(888, 5, std::bind(DelTest, t));

    for(int i = 0; i < 5; i++)
    {
        sleep(1);
        tw.TimerRefresh(888); //刷新定时任务
        tw.RunTimerTask();    //向后移动秒针
        std::cout << "刷新了一下定时任务，重新需要5s钟后才销毁\n";
    }
    tw.TimerCancel(888);

    while(1)
    {
        sleep(1);
        std::cout << "--------------------\n";
        tw.RunTimerTask();   //向后移动秒针
    }

    return 0;
}